Add RandR 1.2 support
authorSøren Sandmann <sandmann@redhat.com>
Thu, 13 Dec 2007 18:27:05 +0000 (18:27 +0000)
committerSøren Sandmann Pedersen <ssp@src.gnome.org>
Thu, 13 Dec 2007 18:27:05 +0000 (18:27 +0000)
Thu Dec 13 13:14:50 2007  Søren Sandmann  <sandmann@redhat.com>

        * Add RandR 1.2 support

        - New monitors_changed signal - New API to get width/height of
          monitors, and the name of the plug

svn path=/trunk/; revision=19173

ChangeLog
configure.in
gdk/gdk.symbols
gdk/gdkscreen.c
gdk/gdkscreen.h
gdk/x11/gdkdisplay-x11.c
gdk/x11/gdkdisplay-x11.h
gdk/x11/gdkevents-x11.c
gdk/x11/gdkscreen-x11.c
gdk/x11/gdkscreen-x11.h
gdk/x11/gdkx.h

index 5fa4e99e416ba1279c0653e83875e32774cedafc..4cc50d6cfcb077a1a38ae238ce7eb849512e957a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Thu Dec 13 13:14:50 2007  Søren Sandmann  <sandmann@redhat.com>
+
+       * Add RandR 1.2 support
+
+       - New monitors_changed signal - New API to get width/height of
+         monitors, and the name of the plug
+
 2007-12-13  Kristian Rietveld  <kris@imendio.com>
 
        * gtk/tests/liststore.c:
index 0741e53c0513f75296ab66a6429307831f8c2d78..fbab5bb3c57ffd8d7907934095f29ed82f2157de 100644 (file)
@@ -1325,19 +1325,10 @@ if test "x$gdktarget" = "xx11"; then
   AM_CONDITIONAL(XINPUT_XFREE, test x$with_xinput = xxfree || test x$with_xinput = xyes)
 
   # Check for the RANDR extension
+  if $PKG_CONFIG --exists "xrandr >= 1.2" ; then
+     AC_DEFINE(HAVE_RANDR, 1, Have the Xrandr extension library)
 
-  have_randr=false
-  if $PKG_CONFIG --exists xrandr ; then
-    have_randr=true
-    X_PACKAGES="$X_PACKAGES xrandr"
-  else    
-    AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
-       [AC_CHECK_HEADER(X11/extensions/Xrandr.h,
-          # RANDR requires RENDER
-          [have_randr=true
-          GTK_ADD_LIB(x_extra_libs, Xrender)
-          GTK_ADD_LIB(x_extra_libs, Xrandr)],
-         :, [#include <X11/Xlib.h>])])
+     X_PACKAGES="$X_PACKAGES xrandr"
   fi
 
   if $have_randr ; then
index 40f05a2f5e88d3369dd099b1b6a0f2b2e94b2411..71f8c9e9cd695afde08d4c38c7c900eb012ab6dd 100644 (file)
@@ -1056,6 +1056,9 @@ gdk_screen_get_default_colormap
 gdk_screen_set_default_colormap
 gdk_screen_get_n_monitors
 gdk_screen_get_monitor_geometry
+gdk_screen_get_monitor_width_mm 
+gdk_screen_get_monitor_height_mm
+gdk_screen_get_monitor_plug_name
 gdk_screen_get_rgba_colormap
 gdk_screen_get_rgba_visual
 gdk_screen_get_active_window
@@ -1234,6 +1237,7 @@ gdk_x11_image_get_ximage
 #if IN_FILE(__GDK_SCREEN_X11_C__)
 gdk_x11_screen_get_screen_number
 gdk_x11_screen_get_xscreen
+gdk_x11_screen_get_monitor_output
 #endif
 
 #if IN_FILE(__GDK_VISUAL_X11_C__)
index 986f9f5525dbc1538a6e285a0afca95ac7d3b7e7..72aa3f731348020a99646bbd0cb09c4c48c0faa9 100644 (file)
@@ -51,6 +51,7 @@ enum
 {
   SIZE_CHANGED,
   COMPOSITED_CHANGED,
+  MONITORS_CHANGED,
   LAST_SIGNAL
 };
 
@@ -124,6 +125,28 @@ gdk_screen_class_init (GdkScreenClass *klass)
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE,
                  0);
+       
+  /**
+   * GdkScreen::monitors-changed:
+   * @screen: the object on which the signal is emitted
+   *
+   * The ::monitors_changed signal is emitted when the number, size
+   * or position of the monitors attached to the screen change. 
+   *
+   * Only for X for now. Future implementations for Win32 and
+   * OS X may be a possibility.
+   *
+   * Since: 2.14
+   */
+  signals[MONITORS_CHANGED] =
+    g_signal_new (g_intern_static_string ("monitors_changed"),
+                 G_OBJECT_CLASS_TYPE (klass),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GdkScreenClass, monitors_changed),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE,
+                 0);
 }
 
 static void
index 7ff920193fa86e29979f6de83c935e9cd84122a6..c89990335d42904d7700b5060c36c851184ac654 100644 (file)
@@ -58,6 +58,7 @@ struct _GdkScreenClass
 
   void (*size_changed) (GdkScreen *screen);
   void (*composited_changed) (GdkScreen *screen);
+  void (*monitors_changed) (GdkScreen *screen);
 };
 
 GType        gdk_screen_get_type              (void) G_GNUC_CONST;
@@ -93,6 +94,12 @@ gint          gdk_screen_get_monitor_at_point  (GdkScreen *screen,
                                                gint       y);
 gint          gdk_screen_get_monitor_at_window (GdkScreen *screen,
                                                GdkWindow *window);
+gint          gdk_screen_get_monitor_width_mm  (GdkScreen *screen,
+                                                gint       monitor_num);
+gint          gdk_screen_get_monitor_height_mm (GdkScreen *screen,
+                                                gint       monitor_num);
+gchar *       gdk_screen_get_monitor_plug_name (GdkScreen *screen,
+                                                gint       monitor_num);
 
 void          gdk_screen_broadcast_client_message  (GdkScreen       *screen,
                                                    GdkEvent        *event);
index 89aedfa3f2df224bdfb12280e705a7fd7dbac340..56eccc91f114ef982f2af43902cc96c056820385 100644 (file)
 #include <X11/extensions/Xdamage.h>
 #endif
 
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
 
 static void   gdk_display_x11_dispose            (GObject            *object);
 static void   gdk_display_x11_finalize           (GObject            *object);
@@ -165,6 +169,21 @@ gdk_display_open (const gchar *display_name)
   XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
 #endif /* HAVE_X11R6 */
   
+  /* RandR must be initialized before we initialize the screens */
+  display_x11->have_randr12 = FALSE;
+#ifdef HAVE_RANDR
+  if (XRRQueryExtension (display_x11->xdisplay,
+                        &display_x11->xrandr_event_base, &ignore))
+  {
+      int major, minor;
+      
+      XRRQueryVersion (display_x11->xdisplay, &major, &minor);
+
+      if ((major == 1 && minor >= 2) || major > 1)
+         display_x11->have_randr12 = TRUE;
+  }
+#endif
+  
   /* initialize the display's screens */ 
   display_x11->screens = g_new (GdkScreen *, ScreenCount (display_x11->xdisplay));
   for (i = 0; i < ScreenCount (display_x11->xdisplay); i++)
index 7b2654cd7c9901576daadbcd4d5e43ddecc080a8..ffd04611137594652e1a081d88ca098ce1d52313 100644 (file)
@@ -85,6 +85,9 @@ struct _GdkDisplayX11
   gboolean have_xdamage;
   gint xdamage_event_base;
 
+  gboolean have_randr12;
+  gint xrandr_event_base;
+
   /* If the SECURITY extension is in place, whether this client holds 
    * a trusted authorization and so is allowed to make various requests 
    * (grabs, properties etc.) Otherwise always TRUE. */
index d55b572dd54a21ec37fd926cda9f894b8aee3296..a537ffc75a65936479e32dc29fe2f87141adbc52 100644 (file)
 #include <X11/extensions/Xfixes.h>
 #endif
 
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
 #include <X11/Xatom.h>
 
 typedef struct _GdkIOClosure GdkIOClosure;
@@ -2102,6 +2106,16 @@ gdk_event_translate (GdkDisplay *display,
        }
       else
 #endif
+#ifdef HAVE_RANDR
+      if (xevent->type - display_x11->xrandr_event_base == RRNotify)
+       {
+           XRRNotifyEvent *notify = (XRRNotifyEvent *)xevent;
+           
+           if (screen)
+               _gdk_x11_screen_process_monitors_change (screen);
+       }
+      else 
+#endif
 #if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
       if (display_x11->have_xdamage && window_private && window_private->composited &&
          xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
index 624870f850f2e84c42b945ac90c36cea7788c5ea..469f9b6c2aa1f413bac17593b9708a9bd0e473ea 100644 (file)
@@ -53,8 +53,8 @@
 
 static void         gdk_screen_x11_dispose     (GObject                  *object);
 static void         gdk_screen_x11_finalize    (GObject                  *object);
-static void        init_xinerama_support      (GdkScreen         *screen);
 static void        init_randr_support         (GdkScreen         *screen);
+static void        deinit_multihead           (GdkScreen         *screen);
 
 enum
 {
@@ -66,6 +66,16 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (GdkScreenX11, _gdk_screen_x11, GDK_TYPE_SCREEN)
 
+struct _GdkX11Monitor
+{
+  GdkRectangle  geometry;
+  XID          output;
+  int          width_mm;
+  int          height_mm;
+  char *       output_name;
+  char *       manufacturer;
+};
+
 static void
 _gdk_screen_x11_class_init (GdkScreenX11Class *klass)
 {
@@ -321,8 +331,8 @@ gdk_screen_x11_finalize (GObject *object)
 
   g_hash_table_destroy (screen_x11->colormap_hash);
 
-  g_free (screen_x11->monitors);
-
+  deinit_multihead (GDK_SCREEN (object));
+  
   G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->finalize (object);
 }
 
@@ -341,7 +351,100 @@ gdk_screen_get_n_monitors (GdkScreen *screen)
 {
   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
   
-  return GDK_SCREEN_X11 (screen)->num_monitors;
+  return GDK_SCREEN_X11 (screen)->n_monitors;
+}
+
+static GdkX11Monitor *
+get_monitor (GdkScreen *screen,
+            int        monitor_num)
+{
+  GdkScreenX11 *screen_x11;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+  
+  screen_x11 = GDK_SCREEN_X11 (screen);
+  
+  g_return_val_if_fail (monitor_num < screen_x11->n_monitors, NULL);
+  g_return_val_if_fail (monitor_num >= 0, NULL);
+  
+  return &(screen_x11->monitors[monitor_num]);
+}
+
+/**
+ * gdk_screen_get_monitor_width_mm:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor
+ *
+ * Gets the width in millimeters of the specified monitor, if available.
+ *
+ * Returns the width of the monitor, or -1 if not available;
+ *
+ * Since: 2.14
+ */
+gint
+gdk_screen_get_monitor_width_mm        (GdkScreen *screen,
+                                gint       monitor_num)
+{
+  return get_monitor (screen, monitor_num)->width_mm;
+}
+
+/**
+ * gdk_screen_get_monitor_height_mm:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor
+ *
+ * Gets the height in millimeters of the specified monitor. 
+ *
+ * Returns: the height of the monitor
+ *
+ * Since: 2.14
+ */
+gint
+gdk_screen_get_monitor_height_mm (GdkScreen *screen,
+                                  gint       monitor_num)
+{
+  return get_monitor (screen, monitor_num)->height_mm;
+}
+
+/**
+ * gdk_screen_get_monitor_plug_name:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor
+ *
+ * Returns the output name of the specified monitor. 
+ * Usually something like VGA, DVI, or TV, not the actual
+ * product name of the display device.
+ * 
+ * Returns: a newly-allocated string containing the name of the monitor,
+ *   or %NULL if the name cannot be determined
+ *
+ * Since: 2.14
+ */
+gchar *
+gdk_screen_get_monitor_plug_name (GdkScreen *screen,
+                                 gint       monitor_num)
+{
+  return g_strdup (get_monitor (screen, monitor_num)->output_name);
+}
+
+/**
+ * gdk_x11_screen_get_monitor_output:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor 
+ *
+ * Gets the XID of the specified output/monitor.
+ * If the X server does not support version 1.2 of the RANDR 
+ * extension, 0 is returned.
+ *
+ * Returns: the XID of the monitor
+ *
+ * Since: 2.14
+ */
+XID
+gdk_x11_screen_get_monitor_output (GdkScreen *screen,
+                                   gint       monitor_num)
+{
+  return get_monitor (screen, monitor_num)->output;
 }
 
 /**
@@ -363,11 +466,12 @@ gdk_screen_get_monitor_geometry (GdkScreen    *screen,
                                 gint          monitor_num,
                                 GdkRectangle *dest)
 {
-  g_return_if_fail (GDK_IS_SCREEN (screen));
-  g_return_if_fail (monitor_num < GDK_SCREEN_X11 (screen)->num_monitors);
-  g_return_if_fail (monitor_num >= 0);
+  if (dest) 
+    {
+      GdkX11Monitor *monitor = get_monitor (screen, monitor_num);
 
-  *dest = GDK_SCREEN_X11 (screen)->monitors[monitor_num];
+      *dest = monitor->geometry;
+    }
 }
 
 /**
@@ -452,7 +556,6 @@ gdk_x11_screen_get_xscreen (GdkScreen *screen)
   return GDK_SCREEN_X11 (screen)->xscreen;
 }
 
-
 /**
  * gdk_x11_screen_get_screen_number:
  * @screen: a #GdkScreen.
@@ -490,6 +593,287 @@ make_cm_atom (int screen_number)
   return atom;
 }
 
+static void
+init_monitor_geometry (GdkX11Monitor *monitor,
+                      int x, int y, int width, int height)
+{
+  monitor->geometry.x = x;
+  monitor->geometry.y = y;
+  monitor->geometry.width = width;
+  monitor->geometry.height = height;
+
+  monitor->output = None;
+  monitor->width_mm = -1;
+  monitor->height_mm = -1;
+  monitor->output_name = NULL;
+  monitor->manufacturer = NULL;
+}
+
+static gboolean
+init_fake_xinerama (GdkScreen *screen)
+{
+#ifdef G_ENABLE_DEBUG
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  XSetWindowAttributes atts;
+  Window win;
+  gint w, h;
+
+  if (!(_gdk_debug_flags & GDK_DEBUG_XINERAMA))
+    return FALSE;
+  
+  /* Fake Xinerama mode by splitting the screen into 4 monitors.
+   * Also draw a little cross to make the monitor boundaries visible.
+   */
+  w = WidthOfScreen (screen_x11->xscreen);
+  h = HeightOfScreen (screen_x11->xscreen);
+
+  screen_x11->n_monitors = 4;
+  screen_x11->monitors = g_new0 (GdkX11Monitor, 4);
+  init_monitor_geometry (&screen_x11->monitors[0], 0, 0, w / 2, h / 2);
+  init_monitor_geometry (&screen_x11->monitors[1], w / 2, 0, w / 2, h / 2);
+  init_monitor_geometry (&screen_x11->monitors[2], 0, h / 2, w / 2, h / 2);
+  init_monitor_geometry (&screen_x11->monitors[3], w / 2, h / 2, w / 2, h / 2);
+  
+  atts.override_redirect = 1;
+  atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen), 
+                                    screen_x11->screen_num);
+  win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
+                     screen_x11->xroot_window, 0, h / 2, w, 1, 0, 
+                     DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
+                                  screen_x11->screen_num),
+                     InputOutput, 
+                     DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
+                                   screen_x11->screen_num),
+                     CWOverrideRedirect|CWBackPixel, 
+                     &atts);
+  XMapRaised(GDK_SCREEN_XDISPLAY (screen), win); 
+  win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
+                     screen_x11->xroot_window, w/2 , 0, 1, h, 0, 
+                     DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
+                                  screen_x11->screen_num),
+                     InputOutput, 
+                     DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
+                                   screen_x11->screen_num),
+                     CWOverrideRedirect|CWBackPixel, 
+                     &atts);
+  XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
+  return TRUE;
+#endif
+  
+  return FALSE;
+}
+
+static gboolean
+init_randr12 (GdkScreen *screen)
+{
+#ifdef HAVE_RANDR
+  GdkDisplay *display = gdk_screen_get_display (screen);
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+  XRRScreenResources *resources;
+  int i;
+  GArray *monitors;
+
+  if (!display_x11->have_randr12)
+      return FALSE;
+
+  monitors = g_array_new (TRUE, TRUE, sizeof (GdkX11Monitor));
+  
+  resources = XRRGetScreenResources (screen_x11->xdisplay,
+                                    screen_x11->xroot_window);
+  
+  /* FIXME: can GetScreenResources return NULL except when it's out of memory? */
+  for (i = 0; i < resources->noutput; ++i)
+    {
+      XRROutputInfo *output =
+       XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
+
+      if (output->crtc)
+       {
+         GdkX11Monitor monitor;
+         XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);
+
+         monitor.geometry.x = crtc->x;
+         monitor.geometry.y = crtc->y;
+         monitor.geometry.width = crtc->width;
+         monitor.geometry.height = crtc->height;
+
+         /* FIXME: fill this out properly - need EDID parser */
+         monitor.output = resources->outputs[i];
+         monitor.width_mm = -1;
+         monitor.height_mm = -1;
+         monitor.output_name = NULL;
+         monitor.manufacturer = NULL;
+
+         g_array_append_val (monitors, monitor);
+       }
+
+      XRRFreeOutputInfo (output);
+    }
+
+  screen_x11->n_monitors = monitors->len;
+  screen_x11->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
+  
+  return TRUE;
+#endif
+  
+  return FALSE;
+}
+
+static gboolean
+init_solaris_xinerama (GdkScreen *screen)
+{
+#ifdef HAVE_SOLARIS_XINERAMA
+  Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+  int screen_no = gdk_screen_get_number (screen);
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  XRectangle monitors[MAXFRAMEBUFFERS];
+  unsigned char hints[16];
+  gint result;
+  int n_monitors;
+  int i;
+  
+  if (!XineramaGetState (dpy, screen_no))
+    return FALSE;
+
+  result = XineramaGetInfo (dpy, screen_no, monitors, hints, &n_monitors);
+
+  /* Yes I know it should be Success but the current implementation 
+   * returns the num of monitor
+   */
+  if (result == 0)
+    {
+      /* FIXME: We need to trap errors, since
+       * XINERAMA isn't always XINERAMA.
+       */ 
+      g_error ("error while retrieving Xinerama information");
+    }
+
+  screen_x11->monitors = g_new0 (GdkX11Monitor, n_rects);
+  screen_x11->n_monitors = n_rects;
+
+  for (i = 0; i < n_rects; i++)
+    {
+      init_monitor_geometry (&screen_x11->monitors[i],
+                            rects[i].x, rects[i].y,
+                            rects[i].width, rects[i].height);
+    }
+  
+  return TRUE;
+#endif /* HAVE_SOLARIS_XINERAMA */
+
+  return FALSE;
+}
+
+static gboolean
+init_xfree_xinerama (GdkScreen *screen)
+{
+#ifdef HAVE_XFREE_XINERAMA
+  Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  XineramaScreenInfo *monitors;
+  int i, n_monitors;
+  
+  if (!XineramaIsActive (dpy))
+    return FALSE;
+
+  monitors = XineramaQueryScreens (dpy, &n_monitors);
+  
+  if (n_monitors <= 0 || monitors == NULL)
+    {
+      /* If Xinerama doesn't think we have any monitors, try acting as
+       * though we had no Xinerama. If the "no monitors" condition
+       * is because XRandR 1.2 is currently switching between CRTCs,
+       * we'll be notified again when we have our monitor back,
+       * and can go back into Xinerama-ish mode at that point.
+       */
+      if (monitors)
+       XFree (monitors);
+      
+      return FALSE;
+    }
+
+  screen_x11->n_monitors = n_monitors;
+  screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
+  
+  for (i = 0; i < n_monitors; ++i)
+    {
+      init_monitor_geometry (&screen_x11->monitors[i],
+                            monitors[i].x_org, monitors[i].y_org,
+                            monitors[i].width, monitors[i].height);
+    }
+  
+  XFree (monitors);
+  
+  return TRUE;
+#endif /* HAVE_XFREE_XINERAMA */
+  
+  return FALSE;
+}
+
+static void
+deinit_multihead (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  int i;
+
+  for (i = 0; i < screen_x11->n_monitors; ++i)
+    {
+      GdkX11Monitor *monitor = get_monitor (screen, i);
+
+      g_free (monitor->output_name);
+      g_free (monitor->manufacturer);
+    }
+
+  g_free (screen_x11->monitors);
+
+  screen_x11->n_monitors = 0;
+  screen_x11->monitors = NULL;
+}
+
+static void
+init_multihead (GdkScreen *screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  int opcode, firstevent, firsterror;
+
+  deinit_multihead (screen);
+  
+  /* There are four different implementations of multihead support: 
+   *
+   *  1. Fake Xinerama for debugging purposes
+   *  2. RandR 1.2
+   *  3. Solaris Xinerama
+   *  4. XFree86/Xorg Xinerama
+   *
+   * We use them in that order.
+   */
+  if (init_fake_xinerama (screen))
+    return;
+
+  if (init_randr12 (screen))
+    return;
+
+  if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
+                      &opcode, &firstevent, &firsterror))
+    {
+      if (init_solaris_xinerama (screen))
+       return;
+      
+      if (init_xfree_xinerama (screen))
+       return;
+    }
+
+  /* No multihead support of any kind for this screen */
+  screen_x11->n_monitors = 1;
+  screen_x11->monitors = g_new0 (GdkX11Monitor, 1);
+
+  init_monitor_geometry (screen_x11->monitors, 0, 0,
+                        WidthOfScreen (screen_x11->xscreen),
+                        HeightOfScreen (screen_x11->xscreen));
+}
+
 GdkScreen *
 _gdk_x11_screen_new (GdkDisplay *display,
                     gint        screen_number) 
@@ -512,7 +896,7 @@ _gdk_x11_screen_new (GdkDisplay *display,
   screen_x11->cm_selection_atom = make_cm_atom (screen_number);
   screen_x11->is_composited = check_is_composited (display, screen_x11);
   
-  init_xinerama_support (screen);
+  init_multihead (screen);
   init_randr_support (screen);
   
   _gdk_visual_init (screen);
@@ -549,185 +933,6 @@ gdk_screen_is_composited (GdkScreen *screen)
   return screen_x11->is_composited;
 }
 
-#ifdef HAVE_XINERAMA
-static gboolean
-check_solaris_xinerama (GdkScreen *screen)
-{
-#ifdef HAVE_SOLARIS_XINERAMA
-  
-  if (XineramaGetState (GDK_SCREEN_XDISPLAY (screen),
-                       gdk_screen_get_number (screen)))
-    {
-      XRectangle monitors[MAXFRAMEBUFFERS];
-      unsigned char hints[16];
-      gint result;
-      GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-
-      result = XineramaGetInfo (GDK_SCREEN_XDISPLAY (screen),
-                               gdk_screen_get_number (screen),
-                               monitors, hints,
-                               &screen_x11->num_monitors);
-      /* Yes I know it should be Success but the current implementation 
-          returns the num of monitor*/
-      if (result == 0)
-       {
-         /* FIXME: We need to trap errors, since XINERAMA isn't always XINERAMA.
-          */ 
-         g_error ("error while retrieving Xinerama information");
-       }
-      else
-       {
-         int i;
-         screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
-         
-         for (i = 0; i < screen_x11->num_monitors; i++)
-           {
-             screen_x11->monitors[i].x = monitors[i].x;
-             screen_x11->monitors[i].y = monitors[i].y;
-             screen_x11->monitors[i].width = monitors[i].width;
-             screen_x11->monitors[i].height = monitors[i].height;
-           }
-
-         return TRUE;
-       }
-    }
-#endif /* HAVE_SOLARIS_XINERAMA */
-  
-  return FALSE;
-}
-
-static gboolean
-check_xfree_xinerama (GdkScreen *screen)
-{
-#ifdef HAVE_XFREE_XINERAMA
-  if (XineramaIsActive (GDK_SCREEN_XDISPLAY (screen)))
-    {
-      GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-      XineramaScreenInfo *monitors = XineramaQueryScreens (GDK_SCREEN_XDISPLAY (screen),
-                                                          &screen_x11->num_monitors);
-      if (screen_x11->num_monitors <= 0 || monitors == NULL)
-       {
-         /* If Xinerama doesn't think we have any monitors, try acting as
-          * though we had no Xinerama. If the "no monitors" condition
-          * is because XRandR 1.2 is currently switching between CRTCs,
-          * we'll be notified again when we have our monitor back,
-          * and can go back into Xinerama-ish mode at that point. */
-         if (monitors)
-           XFree (monitors);
-         return FALSE;
-       }
-      else
-       {
-         int i;
-         screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
-         
-         for (i = 0; i < screen_x11->num_monitors; i++)
-           {
-             screen_x11->monitors[i].x = monitors[i].x_org;
-             screen_x11->monitors[i].y = monitors[i].y_org;
-             screen_x11->monitors[i].width = monitors[i].width;
-             screen_x11->monitors[i].height = monitors[i].height;
-           }
-
-         XFree (monitors);
-
-         return TRUE;
-       }
-    }
-#endif /* HAVE_XFREE_XINERAMA */
-  
-  return FALSE;
-}
-#endif /* HAVE_XINERAMA */
-
-static void
-init_xinerama_support (GdkScreen * screen)
-{
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-#ifdef HAVE_XINERAMA
-  int opcode, firstevent, firsterror;
-#endif
-
-  g_free (screen_x11->monitors);
-  
-#ifdef HAVE_XINERAMA  
-  if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
-                      &opcode, &firstevent, &firsterror))
-    {
-      if (check_solaris_xinerama (screen) ||
-         check_xfree_xinerama (screen))
-       return;
-    }
-#endif /* HAVE_XINERAMA */
-
-  /* No Xinerama
-   */
-#ifdef G_ENABLE_DEBUG
-  if (_gdk_debug_flags & GDK_DEBUG_XINERAMA)
-    {
-      /* Fake Xinerama mode by splitting the screen into 4 monitors.
-       * Also draw a little cross to make the monitor boundaries visible.
-       */
-      XSetWindowAttributes atts;
-      Window win;
-      gint w, h;
-
-      w = WidthOfScreen (screen_x11->xscreen);
-      h = HeightOfScreen (screen_x11->xscreen);
-      screen_x11->num_monitors = 4;
-      screen_x11->monitors = g_new0 (GdkRectangle, 4);
-      screen_x11->monitors[0].x = 0;
-      screen_x11->monitors[0].y = 0;
-      screen_x11->monitors[0].width = w / 2;
-      screen_x11->monitors[0].height = h / 2;
-      screen_x11->monitors[1].x = w / 2;
-      screen_x11->monitors[1].y = 0;
-      screen_x11->monitors[1].width = w / 2;
-      screen_x11->monitors[1].height = h / 2;
-      screen_x11->monitors[2].x = 0;
-      screen_x11->monitors[2].y = h / 2;
-      screen_x11->monitors[2].width = w / 2;
-      screen_x11->monitors[2].height = h / 2;
-      screen_x11->monitors[3].x = w / 2;
-      screen_x11->monitors[3].y = h / 2;
-      screen_x11->monitors[3].width = w / 2;
-      screen_x11->monitors[3].height = h / 2;
-      atts.override_redirect = 1;
-      atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen), 
-                                        screen_x11->screen_num);
-      win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
-                         screen_x11->xroot_window, 0, h / 2, w, 1, 0, 
-                         DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
-                                      screen_x11->screen_num),
-                         InputOutput, 
-                         DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
-                                       screen_x11->screen_num),
-                         CWOverrideRedirect|CWBackPixel, 
-                         &atts);
-      XMapRaised(GDK_SCREEN_XDISPLAY (screen), win); 
-      win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
-                         screen_x11->xroot_window, w/2 , 0, 1, h, 0, 
-                         DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
-                                      screen_x11->screen_num),
-                         InputOutput, 
-                         DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
-                                       screen_x11->screen_num),
-                         CWOverrideRedirect|CWBackPixel, 
-                         &atts);
-      XMapRaised(GDK_SCREEN_XDISPLAY (screen), win); 
-    }
-  else
-#endif
-    {
-       screen_x11->num_monitors = 1;
-       screen_x11->monitors = g_new0 (GdkRectangle, 1);
-       screen_x11->monitors[0].x = 0;
-       screen_x11->monitors[0].y = 0;
-       screen_x11->monitors[0].width = WidthOfScreen (screen_x11->xscreen);
-       screen_x11->monitors[0].height = HeightOfScreen (screen_x11->xscreen);
-    }
-}
-
 static void
 init_randr_support (GdkScreen * screen)
 {
@@ -736,6 +941,14 @@ init_randr_support (GdkScreen * screen)
   XSelectInput (GDK_SCREEN_XDISPLAY (screen),
                screen_x11->xroot_window,
                StructureNotifyMask);
+
+#ifdef HAVE_RANDR
+  XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
+                 screen_x11->xroot_window,
+                 RRScreenChangeNotifyMask      |
+                 RRCrtcChangeNotifyMask        |
+                 RROutputPropertyNotifyMask);
+#endif
 }
 
 void
@@ -758,10 +971,18 @@ _gdk_x11_screen_size_changed (GdkScreen *screen,
     return;
 #endif
   
-  init_xinerama_support (screen);
+  init_multihead (screen);
   g_signal_emit_by_name (screen, "size_changed");
 }
 
+void
+_gdk_x11_screen_process_monitors_change (GdkScreen *screen)
+{
+  init_multihead (screen);
+
+  g_signal_emit_by_name (screen, "monitors_changed");
+}
+
 void
 _gdk_x11_screen_window_manager_changed (GdkScreen *screen)
 {
index 6ba8d62999c7096335cfdae69f0a7dc071d03988..c5b191095b5929844ec144167b0b57184352d4f5 100644 (file)
@@ -43,6 +43,8 @@ typedef struct _GdkScreenX11Class GdkScreenX11Class;
 #define GDK_IS_SCREEN_X11_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SCREEN_X11))
 #define GDK_SCREEN_X11_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SCREEN_X11, GdkScreenX11Class))
 
+typedef struct _GdkX11Monitor GdkX11Monitor;
+
 struct _GdkScreenX11
 {
   GdkScreen parent_instance;
@@ -87,9 +89,9 @@ struct _GdkScreenX11
   XSettingsClient *xsettings_client;
   guint xsettings_in_init : 1;
   
-  /* Xinerama */
-  gint     num_monitors;
-  GdkRectangle *monitors;
+  /* Xinerama/RandR 1.2 */
+  gint          n_monitors;
+  GdkX11Monitor        *monitors;
 
   /* Pango renderer object singleton */
   PangoRenderer *renderer;
@@ -124,6 +126,7 @@ void _gdk_x11_screen_size_changed           (GdkScreen *screen,
                                             XEvent    *event);
 void _gdk_x11_screen_process_owner_change (GdkScreen *screen,
                                           XEvent    *event);
+void _gdk_x11_screen_process_monitors_change (GdkScreen *screen);
 
 G_END_DECLS
 
index ec85047913d21ebddf623f969bb9f918e88577bc..64185f82888af71c027eb6340da69e774bc09dff 100644 (file)
@@ -156,6 +156,9 @@ void gdk_x11_display_broadcast_startup_message (GdkDisplay *display,
 gboolean gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
                                              GdkAtom    property);
 
+XID      gdk_x11_screen_get_monitor_output   (GdkScreen *screen,
+                                              gint       monitor_num);
+
 #ifndef GDK_MULTIHEAD_SAFE
 gpointer      gdk_xid_table_lookup   (XID              xid);
 gboolean      gdk_net_wm_supports    (GdkAtom    property);